package com.jflame.tomcat.http;

import com.jflame.tomcat.utils.NamesEnumerator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;

/**
 * Created with IntelliJ IDEA
 * Description:
 * User:22954
 * Date:2024-07-21
 * Time:15:11
 */
public class JFRequest implements HttpServletRequest {
    private String method;
    private String requestURI;
    private String protocol;
    private String requestURL;
    private String queryString;
    private HashMap<String, String> headers;
    private HashMap<String, List<String>> parameters;
    private NamesEnumerator<String> headerNames;
    private BufferedReader br;

    public JFRequest(InputStream is) {
        br = new BufferedReader(new InputStreamReader(is));
        headers = new HashMap<>();
        parameters = new HashMap<>();
        headerNames = new NamesEnumerator<>();
        encapsulation();
    }

    private void encapsulation() {
        try {
            decomposeRequestLine();
            decomposeHeader();
            if (method != null && method.equals("POST")) {
                decomposeBody();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        requestURL = getHeader("origin") + getRequestURI();
        headerNames = new NamesEnumerator<>(headers.keySet());
    }

    private void decomposeRequestLine() throws IOException {
        String line;
        if ((line = br.readLine()) != null && !line.isEmpty()) {
            String[] strings = line.split(" ");
            method = strings[0].toUpperCase();
            if (strings[1].indexOf('?') == -1) {
                requestURI = strings[1];
                queryString = null;
            } else {
                requestURI = strings[1].substring(0, strings[1].indexOf('?'));
                queryString = strings[1].substring(strings[1].indexOf('?') + 1);
                decomposeBody(queryString);
            }
            protocol = strings[2];
        }
    }

    private void decomposeHeader() throws IOException {
        String line;
        while ((line = br.readLine()) != null && !line.isEmpty()) {
            String[] strings = line.split(": ");
            headers.put(strings[0], strings[1]);
        }
    }

    private void decomposeBody() throws IOException {
        String line;
        if ((line = br.readLine()) != null && !line.isEmpty()) {
            decomposeBody(line);
        }
    }

    private void decomposeBody(String line) {
        String[] maps = line.split("&");
        for (String map : maps) {
            String[] strings = map.split("=");
            if (strings.length == 2) {
                if (parameters.containsKey(strings[0])) {
                    parameters.get(strings[0]).add(strings[1]);
                } else {
                    List<String> list = new ArrayList<>();
                    list.add(strings[1]);
                    parameters.put(strings[0], list);
                }
            }
        }
    }

    @Override
    public String getMethod() {
        return method;
    }

    @Override
    public String getRequestURI() {
        return requestURI;
    }

    @Override
    public String getProtocol() {
        return protocol;
    }

    @Override
    public String getRequestURL() {
        return requestURL;
    }

    @Override
    public String getQueryString() {
        return queryString;
    }

    @Override
    public String getHeader(String name) {
        return headers.get(name);
    }


    @Override
    public String getParameter(String name) {
        List<String> strings = parameters.get(name);
        return strings.getFirst();
    }

    @Override
    public String[] getParameterValues(String name) {
        List<String> strings = parameters.get(name);
        String[] values = new String[strings.size()];
        strings.toArray(values);
        return values;
    }

    @Override
    public Enumeration<String> getHeaderNames() {
        return headerNames;
    }
}
